package me.boot.auth.spring.handler;

import lombok.extern.slf4j.Slf4j;
import me.boot.auth.spring.AuthUtils;
import me.boot.auth.spring.model.SpringUser;
import me.boot.auth.spring.service.UserService;
import me.boot.web.common.template.model.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Description:
 * @author: Sylar
 * @date: 2021年12月27日 3:56 下午
 */
@Slf4j
@Component
public class AuthHandler implements
        AuthenticationSuccessHandler,
        AuthenticationFailureHandler,
        LogoutSuccessHandler,
        AccessDeniedHandler,
        AuthenticationEntryPoint,
        InvalidSessionStrategy,
        SessionInformationExpiredStrategy {

    @Autowired
    UserService userService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("登陆成功:" + authentication.getPrincipal());
        Long userId = AuthUtils.getLoginUserId();
        SpringUser user = userService.getById(userId);
        AuthUtils.output(response, Result.newSuccess(user));
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        String errMsg = "登录失败!";
        if (exception instanceof BadCredentialsException ||
                exception instanceof UsernameNotFoundException) {
            errMsg = "账户名或者密码输入错误!";
        } else if (exception instanceof LockedException) {
            errMsg = "账户被锁定，请联系管理员!";
        } else if (exception instanceof CredentialsExpiredException) {
            errMsg = "密码过期，请联系管理员!";
        } else if (exception instanceof AccountExpiredException) {
            errMsg = "账户过期，请联系管理员!";
        } else if (exception instanceof DisabledException) {
            errMsg = "账户被禁用，请联系管理员!";
        }

        log.info(errMsg);
        AuthUtils.output(response, Result.newFaild(errMsg));
    }

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("注销登录");
        if (authentication != null) {
            AuthUtils.output(response, Result.newSuccess("注销登录成功"));
        } else {
            AuthUtils.output(response, Result.newFaild("尚未登录"));
        }
    }

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
        //认证过的用户访问无权限资源时的异常
        log.info("当前没有访问权限");
        AuthUtils.output(response, Result.newFaild("当前没有访问权限"));
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        //匿名用户访问无权限资源时的异常
        log.info("匿名用户没有访问权限");
        AuthUtils.output(response, Result.newFaild(-1, "匿名用户没有访问权限"));
    }

    @Override
    public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        //当session失效后的处理逻辑
        AuthUtils.output(response, Result.newFaild(-1, "登录超时，请重新登录"));
    }

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
        //定制session超时的响应
        AuthUtils.output(event.getResponse(), Result.newFaild(-1, "并发登录，您已被迫下线"));
    }
}
